/* Copyright 2007-2008 dnAnalytics Project.
 *
 * Contributors to this file:
 * Patrick van der Velde
 *
 * This file is part of dnAnalytics.  dnAnalytics is licensed under the 
 * Microsoft Public License. See License.txt for a complete copy of the
 * license.
 */

using System;

namespace dnAnalytics.LinearAlgebra.Solvers.Preconditioners
{
    /// <summary>
    /// A unit preconditioner. This preconditioner does not actually do anything
    /// it is only used when running an <see cref="IIterativeSolver"/> without
    /// a preconditioner.
    /// </summary>
    internal sealed class UnitPreconditioner : IPreConditioner
    {
        /// <summary>
        /// The coefficient matrix on which this preconditioner operates.
        /// Is used to check dimensions on the different vectors that are processed.
        /// </summary>
        private int m_Size;
        
        /// <summary>
        /// Initializes the preconditioner and loads the internal data structures.
        /// </summary>
        /// <param name="matrix">
        /// The matrix upon which the preconditioner is based.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="matrix"/> is <b>null</b>.
        /// </exception>
        /// <exception cref="MatrixNotSquareException">
        /// If <paramref name="matrix"/> is not a square matrix.
        /// </exception>
        public void Initialize(Matrix matrix)
        {
            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (matrix.Rows != matrix.Columns)
            {
                throw new MatrixNotSquareException();
            }

            m_Size = matrix.Rows;
        }

        /// <summary>
        /// Approximates the solution to the matrix equation <b>Ax = b</b>.
        /// </summary>
        /// <param name="rhs">The right hand side vector.</param>
        /// <param name="lhs">The left hand side vector. Also known as the result vector.</param>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="rhs"/> is <b>null</b>.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="lhs"/> is <b>null</b>.
        /// </exception>
        /// <exception cref="NotConformableException">
        ///   <para>
        ///     If <paramref name="rhs"/> and <paramref name="lhs"/> do not have the same size.
        ///   </para>
        ///   <para>
        ///     - or -
        ///   </para>
        ///   <para>
        ///     If the size of <paramref name="rhs"/> is different the number of rows of the 
        ///     coefficient matrix.
        ///   </para>
        /// </exception>
        public void Approximate(Vector rhs, Vector lhs)
        {
            if (rhs == null)
            {
                throw new ArgumentNullException("rhs");
            }

            if (lhs == null)
            {
                throw new ArgumentNullException("lhs");
            }

            if ((lhs.Count != rhs.Count) || (lhs.Count != m_Size))
            {
                throw new NotConformableException();
            }

            rhs.CopyTo(lhs);
        }

        /// <summary>
        /// Approximates the solution to the matrix equation <b>Ax = b</b>.
        /// </summary>
        /// <param name="rhs">The right hand side vector.</param>
        /// <returns>The left hand side vector.</returns>
        /// <exception cref="ArgumentNullException">
        ///   If <paramref name="rhs"/> is <b>null</b>.
        /// </exception>
        /// <exception cref="NotConformableException">
        ///   If the size of <paramref name="rhs"/> is different the number 
        ///   of rows of the coefficient matrix.
        /// </exception>
        public Vector Approximate(Vector rhs)
        {
            if (rhs == null)
            {
                throw new ArgumentNullException("rhs");
            }

            if (rhs.Count != m_Size)
            {
                throw new NotConformableException();
            }

            Vector result = new DenseVector(rhs.Count);
            Approximate(rhs, result);
            return result;
        }
    }
}
